package cn.supermaster.management.schedule.service.impl;

import cn.supermaster.management.common.constant.ScheduleConstant;
import cn.supermaster.management.common.exception.job.TaskException;
import cn.supermaster.management.common.text.Convert;
import cn.supermaster.management.schedule.domain.ScheduleTask;
import cn.supermaster.management.schedule.mapper.ScheduleTaskMapper;
import cn.supermaster.management.schedule.service.IScheduleTaskService;
import cn.supermaster.management.schedule.quartz.CronUtils;
import cn.supermaster.management.schedule.quartz.ScheduleTaskUtils;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * All rights Reserved, Designed By www.super-bytecode.com
 *
 * @ProjectName: supermaster-management
 * @Package: cn.supermaster.management.task.service.impl
 * @ClassName: TaskScheduleServiceImpl11
 * @Description: [定时任务调度信息 服务层]
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2021/1/12 13:22
 * @Version: V1.0
 * @Copyright: 2021 www.super-bytecode.com Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Service
public class ScheduleTaskServiceImpl implements IScheduleTaskService {
    @Autowired
    private Scheduler scheduler;

    @Autowired
    private ScheduleTaskMapper scheduleTaskMapper;

    /**
     * 项目启动时，初始化定时器
     * 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）
     */
    @PostConstruct
    public void init() throws SchedulerException, TaskException {
        scheduler.clear();
        List<ScheduleTask> jobList = scheduleTaskMapper.selectAllScheduleTasks();
        for (ScheduleTask job : jobList) {
            ScheduleTaskUtils.createScheduleJob(scheduler, job);
        }
    }

    /**
     * @Description: [获取quartz调度器的计划任务列表]
     * <p></P>
     * @Title: selectJobList
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task  调度信息
     * @Return: java.util.List<cn.supermaster.management.schedule.domain.ScheduleTask>
     */
    @Override
    public List<ScheduleTask> selectJobList(ScheduleTask task) {
        return scheduleTaskMapper.selectScheduleTaskList(task);
    }

    /**
     * @Description: [通过调度任务ID查询调度信息]
     * <p></P>
     * @Title: selectJobById
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: taskId  调度任务ID
     * @Return: cn.supermaster.management.schedule.domain.ScheduleTask 调度任务对象信息
     */
    @Override
    public ScheduleTask selectJobById(Long taskId) {
        return scheduleTaskMapper.selectScheduleTaskByPrimaryKey(taskId);
    }

    /**
     * @Description: [暂停任务]
     * <p></P>
     * @Title: pauseJob
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task  调度信息
     * @Return: int
     */
    @Override
    @Transactional
    public int pauseJob(ScheduleTask task) throws SchedulerException {
        Long jobId = task.getJobId();
        String jobGroup = task.getJobGroup();
        task.setStatus(ScheduleConstant.Status.PAUSE.getValue());
        int rows = scheduleTaskMapper.updateScheduleTask(task);
        if (rows > 0) {
            scheduler.pauseJob(ScheduleTaskUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }

    /**
     * @Description: [恢复任务]
     * <p></P>
     * @Title: resumeJob
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task  调度信息
     * @Return: int
     */
    @Override
    @Transactional
    public int resumeJob(ScheduleTask task) throws SchedulerException {
        Long jobId = task.getJobId();
        String jobGroup = task.getJobGroup();
        task.setStatus(ScheduleConstant.Status.NORMAL.getValue());
        int rows = scheduleTaskMapper.updateScheduleTask(task);
        if (rows > 0) {
            scheduler.resumeJob(ScheduleTaskUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }

    /**
     * @Description: [删除任务后]
     * <p>所对应的trigger也将被删除</P>
     * @Title: deleteJob
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task
     * @Return: int
     */
    @Override
    @Transactional
    public int deleteJob(ScheduleTask task) throws SchedulerException {
        Long jobId = task.getJobId();
        String jobGroup = task.getJobGroup();
        int rows = scheduleTaskMapper.deleteScheduleTaskById(jobId);
        if (rows > 0) {
            scheduler.deleteJob(ScheduleTaskUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }

    /**
     * @Description: [批量删除调度信息]
     * <p></P>
     * @Title: deleteJobByIds
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: ids  需要删除的数据ID
     * @Return: void
     */
    @Override
    @Transactional
    public void deleteJobByIds(String ids) throws SchedulerException {
        Long[] jobIds = Convert.toLongArray(ids);
        for (Long jobId : jobIds) {
            ScheduleTask job = scheduleTaskMapper.selectScheduleTaskByPrimaryKey(jobId);
            deleteJob(job);
        }
    }

    /**
     * @Description: [任务调度状态修改]
     * <p></P>
     * @Title: changeStatus
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task  调度信息
     * @Return: int
     */
    @Override
    @Transactional
    public int changeStatus(ScheduleTask task) throws SchedulerException {
        int rows = 0;
        String status = task.getStatus();
        if (ScheduleConstant.Status.NORMAL.getValue().equals(status)) {
            rows = resumeJob(task);
        } else if (ScheduleConstant.Status.PAUSE.getValue().equals(status)) {
            rows = pauseJob(task);
        }
        return rows;
    }

    /**
     * @Description: [立即运行任务]
     * <p></P>
     * @Title: run
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task  调度信息
     * @Return: void
     */
    @Override
    @Transactional
    public void run(ScheduleTask task) throws SchedulerException {
        Long jobId = task.getJobId();
        ScheduleTask tmpObj = selectJobById(task.getJobId());
        // 参数
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstant.TASK_PROPERTIES, tmpObj);
        scheduler.triggerJob(ScheduleTaskUtils.getJobKey(jobId, tmpObj.getJobGroup()), dataMap);
    }

    /**
     * @Description: [新增任务]
     * <p></P>
     * @Title: insertJob
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task 调度信息 调度信息
     * @Return: int
     */
    @Override
    @Transactional
    public int insertJob(ScheduleTask task) throws SchedulerException, TaskException {
        task.setStatus(ScheduleConstant.Status.PAUSE.getValue());
        int rows = scheduleTaskMapper.insertScheduleTask(task);
        if (rows > 0) {
            ScheduleTaskUtils.createScheduleJob(scheduler, task);
        }
        return rows;
    }

    /**
     * @Description: [更新任务的时间表达式]
     * <p></P>
     * @Title: updateJob
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task 调度信息
     * @Return: int
     */
    @Override
    @Transactional
    public int updateJob(ScheduleTask task) throws SchedulerException, TaskException {
        ScheduleTask properties = selectJobById(task.getJobId());
        int rows = scheduleTaskMapper.updateScheduleTask(task);
        if (rows > 0) {
            updateSchedulerJob(task, properties.getJobGroup());
        }
        return rows;
    }

    /**
     * @Description: [更新任务]
     * <p></P>
     * @Title: updateSchedulerJob
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: task 任务对象
     * @Param: jobGroup 任务组名
     * @Return: void
     */
    public void updateSchedulerJob(ScheduleTask task, String jobGroup) throws SchedulerException, TaskException {
        Long jobId = task.getJobId();
        // 判断是否存在
        JobKey jobKey = ScheduleTaskUtils.getJobKey(jobId, jobGroup);
        if (scheduler.checkExists(jobKey)) {
            // 防止创建时存在数据问题 先移除，然后在执行创建操作
            scheduler.deleteJob(jobKey);
        }
        ScheduleTaskUtils.createScheduleJob(scheduler, task);
    }

    /**
     * @Description: [校验cron表达式是否有效]
     * <p></P>
     * @Title: checkCronExpressionIsValid
     * @Author: Lance Ting
     * @Date: 2021-01-28
     * @Param: cronExpression  表达式
     * @Return: boolean
     */
    @Override
    public boolean checkCronExpressionIsValid(String cronExpression) {
        return CronUtils.isValid(cronExpression);
    }
}